#include "wl_dns.h"

#include "wl_dns_inner.h"
#include "wl_malloc.h"
#include "sockets.h"
#include "netdb.h"
#include "ql_data_call.h"
#include "wl_socket.h"
#include "wl_trace.h"
#include "ql_rtos.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#define MAX_HOST_LEN 80
#define MAX_IP_LEN 20

typedef struct __wl_dns_message {
    wl_int32        resultcode;
    wl_char         host_name[MAX_HOST_LEN];
    wl_char         host[MAX_IP_LEN];
    wl_dns_callback callback;
    void*           context;
} wl_dns_message;

typedef struct __wl_dns_param {
    wl_char         host_name[MAX_HOST_LEN];
    wl_dns_callback callback;
    void*           context;
    wl_int32        taskid;
} wl_dns_param;


void dns_main_thread(void* param)
{
    wl_dns_param*   dns_param = (wl_dns_param*)param;
    wl_dns_message  dns_message;
    wl_task_message message;

    WLLOGD("dns start");
    if (0 > wl_dns_gethostbyname(dns_param->host_name, dns_message.host)) {
        dns_message.resultcode = WL_DNS_TIMEOUT;
    } else {
        dns_message.resultcode = WL_DNS_SUCCESS;
    }
    strncpy(dns_message.host_name, dns_param->host_name, sizeof(dns_message.host_name));
    WLLOGD("dns host %s ip %s", dns_param->host_name, dns_message.host);
    dns_message.host_name[sizeof(dns_message.host_name) - 1] = '\0';
    dns_message.host[sizeof(dns_message.host) - 1]           = '\0';
    dns_message.callback                                     = dns_param->callback;
    dns_message.context                                      = dns_param->context;

    //发送消息
    memset(&message, 0, sizeof(wl_task_message));
    message.type = WL_TASK_MSG_DNS;
    memcpy(&message.data, &dns_message, sizeof(wl_dns_message));
    message.datalen = sizeof(wl_dns_message);
    wl_send_task_message(dns_param->taskid, &message);

    wl_free(param);

    WLLOGT("dns exit");

    ql_task_t task;
    ql_rtos_task_get_current_ref(&task);
    ql_rtos_task_delete(task);
}

wl_int32 wl_dns_async_gethostbyname(wl_char* host_name, wl_dns_callback callback, void* context, wl_int32 taskid) {
    wl_dns_param* dns_param = wl_null;
    dns_param               = (wl_dns_param*)wl_malloc(sizeof(wl_dns_param));
    if (wl_null == dns_param) {
        WLLOGW("malloc fail");
        return -1;
    }
    if (wl_null == host_name || strlen(host_name) <= 0) {
        WLLOGW("host name invalid");
        return -1;
    }
    strncpy(dns_param->host_name, host_name, sizeof(dns_param->host_name));
    dns_param->host_name[sizeof(dns_param->host_name) - 1] = '\0';
    dns_param->callback                                    = callback;
    dns_param->context                                     = context;
    dns_param->taskid                                      = taskid;

    ql_task_t task;
    if (0 != ql_rtos_task_create(&task, 2 * 1024, 100, "wlsdk_dns", dns_main_thread, dns_param)) {
        wl_free(dns_param);
        return -1;
    }

    return 0;
}

wl_int32 wl_dns_gethostbyname(wl_char* host_name, wl_char* host) {
    struct addrinfo *res;
    struct addrinfo hints;
    int ret;
    char ip4_addr_str[16] = {0};
    
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET; /* Allow IPv4 */
    hints.ai_flags = AI_PASSIVE;/* For wildcard IP address */
    hints.ai_protocol = 0; /* Any protocol */
    hints.ai_socktype = SOCK_STREAM;

    ret = getaddrinfo_with_pcid(host_name, NULL, &hints, &res, 1);
    if (ret == 0) {
        struct sockaddr_in	*ip4_svr_addr = (struct sockaddr_in *)res->ai_addr;
        inet_ntop(AF_INET, &(ip4_svr_addr->sin_addr), ip4_addr_str, sizeof(ip4_addr_str));
        WLLOGD("ip: %s\r\n", ip4_addr_str);
    }else {
        WLLOGW("gethostbyname host_name %s fail", host_name);
        return -1;
    }
    // IP地址
    if (res->ai_addr) {
        wl_in_addr in_addr;
        in_addr.s_addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;
        return wl_socket_inet_ntoa(&in_addr, host);
    }
    WLLOGW("host_name %s no ip", host_name);
    return -1;
}

wl_int32 wl_dns_process_message(wl_task_message* message) {
    wl_dns_message dns_message;
    if (wl_null == message || sizeof(wl_dns_message) != message->datalen) {
        WLLOGW("message is null");
        return -1;
    }
    memcpy(&dns_message, &(message->data), message->datalen);
    if (dns_message.callback) {
        dns_message.callback(dns_message.resultcode, dns_message.host_name, dns_message.host, dns_message.context);
    }
    return 0;
}

#ifdef __cplusplus
}
#endif /* __cplusplus */
